package org.rasterfun.language2.example

import org.rasterfun.language2.Conversions._
import org.rasterfun.ArrayBackedImage
import org.rasterfun.ArrayGenerator
import org.rasterfun.language2.LangMath._
import org.rasterfun.utils.{RasterPanel, ImagePanel, SimpleFrame, Rectangle}
import org.rasterfun.language2.num.Num

/**
 * 
 * 
 * @author Hans Haggstrom
 */
object LangExample {
  def main(args: Array[String]) {


    // TODO: Define function etc
    // Instantiate a function object that should be called?
    // When code is generated, it is generated where the results are first used or so.  Results are cached in local vars or such.  Code is a function call, passing in an array and the indexes in it to write the result params to?
    // TODO: For now, just inline all function implementations...  Count number of usages for each expression, if 1 it can be inlined, if more than 1, store in local final field.
    /*
    case class FooEffect{
      val result1 = NumResult
      val result2 = NumResult
      val result3 = BoolResult

      def definition {
        val h = bar ...
        val rgb = RgbExtractor(h, s, b)

        result1 := rgb.r + foo
        result2 := rgb.g * Num(0.5)
        result3 := rgb.b > rgb.r
      }
    }

    or, return a tuple instead with result values / references to the function call results


    val calculateFoo = define { (a: Num, b: Num) =>
        val h = bar ...
        val (r, g, b) = extractRgb(h, s, b)

        val a = lerp(r, 0, foo)
        val b = g * Num(0.5)
        val c = b > rgb.r

        (a, b, c)
    }

    // In some other function
    val (r, g, b) = calculateFoo(x, y)


    def calculateFoo(a: Num, b: Num) {
        parameters(a, b)
        val h = bar ...
        val (r, g, b) = extractRgb(h, s, b)

        val a = lerp(r, 0, foo)
        val b = g * Num(0.5)
        val c = b > rgb.r

        result(a, b, c)
    }

    // In some other function
    val (r, g, b) = calculateFoo(x, y)


     */


    val renderer = ArrayGenerator { (x: Num, y: Num) =>

      def lerp(t: Num, a: Num, b: Num): Num = {
        a * (Num.One - t) + b * t
      }

      val j = x + y - Num(2)
      val i = lerp(y, x, Num(10))
      val red = (y > Num(22)) ? (Num(1) otherwise (i * i) )
      val green = (j > i) ? (j otherwise i * Num(2) )
      val blue = red * Num(5) + (j > i) ? (Num(1) otherwise j * i + red )

      (red,green,blue)
    }

    val renderer2 = ArrayGenerator { (x: Num, y: Num) =>

      def noiseLayer(scale: Double, amplitudeDiv: Double): Num = {
        noise(x * Num(scale), y * Num(scale)) / Num(amplitudeDiv * 2)
      }

      val a = sin( x / y )

      val r = (a > 0) ? (1 otherwise 0)

      val t = noiseLayer(1, 1) + noiseLayer(2, 2) + noiseLayer(4, 4) + 0.5
      val t2 = sin(t * 10)

      val red = abs(noise(x,y,t))
      val green: Num = 0
      val blue = t

      (red,green,blue)
    }

    
    val image = new ArrayBackedImage(512, 512)
    val zoom = 1.3f;
    val coordinates = Rectangle(-zoom, -zoom, 2*zoom, 2*zoom)

    renderer2.generate(image, coordinates)

    new SimpleFrame("Rasterfun example 1", new RasterPanel(renderer2))

    /*

    // Any function that takes two number parameters and returns three (or four) number parameters can be used to create an rgb(a) image.
    val renderer = render2D { (x: Num, y: Num) =>
      val red = ...
      val green = ...
      val blue = ...
      val alpha = ...
      (red,green,blue,alpha)
    }


   renderer.render(arrayImage)

     */

  }
}

